from rest_framework import serializers

from goods.models import SKU
from .models import OrderInfo, OrderGoods
from users.models import Address
from datetime import datetime
from django_redis import get_redis_connection
from django.db import transaction
import time


class OrderCreateSerializer(serializers.Serializer):
    # 不使用ModelSerializer的原因：
    # 1.参数address与模型类属性address的意义不同
    # 2.方法create()表示创建指定模型类的对象，而当前还需要创建订单商品对象
    address = serializers.IntegerField(write_only=True)
    pay_method = serializers.IntegerField(write_only=True)
    order_id = serializers.CharField(read_only=True)

    def validate_address(self, value):
        if Address.objects.filter(pk=value).count() <= 0:
            raise serializers.ValidationError('无效的收货地址')
        return value

    def validate_pay_method(self, value):
        if value not in [1, 2]:
            raise serializers.ValidationError('无效的支付方式')
        return value

    def create(self, validated_data):
        user = self.context['request'].user
        address_id = validated_data.get('address')
        pay_method = validated_data.get('pay_method')

        # 在如下代码中启用事务，否则事务代码无效
        with transaction.atomic():
            # 创建事务
            sid = transaction.savepoint()
            # 1.创建OrderInfo对象
            total_count = 0
            total_amount = 0
            order = OrderInfo.objects.create(
                order_id=datetime.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id,
                user=user,
                address_id=address_id,
                total_count=0,
                total_amount=0,
                freight=10,
                pay_method=pay_method
            )

            # 2.从redis中读取选中的商品
            redis_cli = get_redis_connection('cart')
            # 读取选中的商品编号
            sku_ids = redis_cli.smembers('cart_selected_%d' % user.id)
            sku_ids = [int(sku_id) for sku_id in sku_ids]
            # 读取商品编号及数量
            sku_dict = redis_cli.hgetall('cart_%d' % user.id)
            sku_dict = {int(sku_id): int(count) for sku_id, count in sku_dict.items()}

            # 3.查询选中的商品对象
            skus = SKU.objects.filter(pk__in=sku_ids)

            # 4.遍历
            for sku in skus:
                # 4.1判断库存，如果不足回报错
                count = sku_dict[sku.id]
                if sku.stock < count:
                    # 回滚事务，放弃之前保存的数据
                    transaction.savepoint_rollback(sid)
                    raise serializers.ValidationError('库存不足')

                # 模拟并发
                # time.sleep(5)

                # 4.2如果足够，则修改商品的库存、销量
                # sku.stock -= count
                # sku.sales += count
                # sku.save()

                # 使用乐观锁解决并发错误
                stock_old = sku.stock
                stock = sku.stock - count
                sales = sku.sales + count
                result = SKU.objects. \
                    filter(pk=sku.id, stock=stock_old). \
                    update(stock=stock, sales=sales)
                # update ... where ....
                # result表示update语句执行的结果，表示修改的行数
                if result == 0:
                    # 未修改表中的数据
                    transaction.savepoint_rollback(sid)
                    raise serializers.ValidationError('服务器忙，请稍候重试')

                # 4.3创建OrderGoods对象
                ordergoods = OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=count,
                    price=sku.price
                )
                # 4.4计算总数量、总金额
                total_count += count
                total_amount += count * sku.price

            # 5.赋值总金额、总数量
            order.total_count = total_count
            order.total_amount = total_amount
            order.save()

            # 提交事务
            transaction.savepoint_commit(sid)

        # 6.删除redis中选中的商品
        redis_cli.delete('cart_selected_%d' % user.id)
        redis_cli.hdel('cart_%d' % user.id, *sku_ids)

        return order
